home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / daten / astrolog / src / charts3.c < prev    next >
C/C++ Source or Header  |  1995-08-11  |  26KB  |  836 lines

  1. /*                                                               -*- C -*-
  2. ** Astrolog (Version 4.40) File: charts3.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. /* $VER: $Id: charts3.c,v 1.2 1995/07/02 22:21:13 tf Exp $ */
  38.  
  39. #include "astrolog.h"
  40.  
  41.  
  42. /*
  43. ******************************************************************************
  44. ** Multiple Chart Scanning Routines.
  45. ******************************************************************************
  46. */
  47.  
  48. /* Search through a day, and print out the times of exact aspects among the  */
  49. /* planets during that day, as specified with the -d switch, as well as the  */
  50. /* times when a planet changes sign or direction. To do this, we cast charts */
  51. /* for the beginning and end of the day, or a part of a day, and do a linear */
  52. /* equation check to see if anything exciting happens during the interval.   */
  53. /* (This is probably the single most complicated procedure in the program.)  */
  54.  
  55. void ChartInDaySearch(fProg)
  56. bool fProg;
  57. {
  58.   char sz[cchSzDef];
  59.  
  60.   int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY],
  61.     sign1[MAXINDAY], sign2[MAXINDAY], D1, D2, occurcount, division, div,
  62.     fYear, yea0, yea1, yea2, i, j, k, l, s1, s2;
  63.  
  64.   real time[MAXINDAY], divsiz, d1, d2, e1, e2, f1, f2, g;
  65.  
  66.   /* If parameter 'fProg' is set, look for changes in a progressed chart. */
  67.  
  68.   fYear = us.fInDayMonth && (Mon2 == 0);
  69.   division = (fYear || fProg) ? 1 : us.nDivision;
  70.   divsiz = 24.0 / (real)division*60.0;
  71.  
  72.   /* If -dY in effect, then search through a range of years. */
  73.  
  74.   yea1 = fProg ? Yea2 : Yea;
  75.   yea2 = fYear ? (yea1 + us.nEphemYears - 1) : yea1;
  76.   for (yea0 = yea1; yea0 <= yea2; yea0++) {
  77.  
  78.   /* If -dm in effect, then search through the whole month, day by day. */
  79.  
  80.   if (us.fInDayMonth) 
  81.   {
  82.     D1 = 1;
  83.  
  84.     if (fYear)
  85.     {
  86.       Mon2 = 1; D2 = DayInYearHi(yea0);
  87.     }
  88.     else D2 = DayInMonth(fProg ? Mon2 : Mon, yea0);
  89.   }
  90.   else D1 = D2 = Day;
  91.  
  92.   /* Start searching the day or days in question for exciting stuff. */
  93.  
  94.   for (Day2 = D1; Day2 <= D2; Day2 = AddDay(Mon, Day2, yea0, 1)) 
  95.   {
  96.     occurcount = 0;
  97.  
  98.     /* Cast chart for beginning of day and store it for future use. */
  99.  
  100.     SetCI(ciCore, fYear ? Mon2 : Mon, Day2, yea0, 0.0, Dst, Zon, Lon, Lat);
  101.  
  102.     if( (us.fProgress = fProg) )
  103.     {
  104.       is.JDp = MdytszToJulian(Mon2, DD, yea0, 0.0, Dst, Zon);
  105.       ciCore = ciMain;
  106.     }
  107.  
  108.     CastChart(fTrue);
  109.  
  110.     for (i = 1; i <= cSign; i++) 
  111.     {
  112.       cp2.cusp[i] = house[i];
  113.       cp2.house[i] = inhouse[i];
  114.     }
  115.  
  116.     for (i = 1; i <= cObj; i++)
  117.     {
  118.       cp2.obj[i] = planet[i];
  119.       cp2.dir[i] = ret[i];
  120.     }
  121.  
  122.     /* Now divide the day into segments and search each segment in turn. */
  123.     /* More segments is slower, but has slightly better time accuracy.   */
  124.  
  125.     for (div = 1; div <= division; div++) 
  126.     {
  127.  
  128.       /* Cast the chart for the ending time of the present segment. The   */
  129.       /* beginning time chart is copied from the previous end time chart. */
  130.  
  131.       SetCI(ciCore, fYear ? Mon2 : Mon, Day2, yea0, 
  132.                     DegToDec(24.0*(real)div/(real)division), Dst, Zon, Lon, Lat);
  133.  
  134.       if (fProg)
  135.       {
  136.         is.JDp = MdytszToJulian(Mon2, DD+1, yea0, 0.0, Dst, Zon);
  137.         ciCore = ciMain;
  138.       }
  139.  
  140.       CastChart(fTrue);
  141.  
  142.       for (i = 1; i <= cSign; i++) 
  143.       {
  144.         cp1.cusp[i] = cp2.cusp[i]; cp1.house[i] = cp2.house[i];
  145.         cp2.cusp[i] = house[i];  cp2.house[i] = inhouse[i];
  146.       }
  147.  
  148.       for (i = 1; i <= cObj; i++) 
  149.       {
  150.         cp1.obj[i] = cp2.obj[i]; cp1.dir[i] = cp2.dir[i];
  151.         cp2.obj[i] = planet[i];  cp2.dir[i] = ret[i];
  152.       }
  153.  
  154.       /* Now search through the present segment for anything exciting. */
  155.  
  156.       for (i = 1; i <= cObj; i++) if (!ignore[i] && (fProg || FThing(i))) 
  157.       {
  158.         s1 = SFromZ(cp1.obj[i])-1;
  159.         s2 = SFromZ(cp2.obj[i])-1;
  160.  
  161.         /* Does the current planet change into the next or previous sign? */
  162.  
  163.         if (!ignore[i] && s1 != s2 && !ignore[0]) 
  164.         {
  165.           source[occurcount] = i;
  166.           aspect[occurcount] = aSig;
  167.           dest[occurcount] = s2+1;
  168.           time[occurcount] = MinDistance(cp1.obj[i],
  169.             (real)(cp1.dir[i] >= 0.0 ? s2 : s1) * 30.0) /
  170.             MinDistance(cp1.obj[i], cp2.obj[i])*divsiz + (real)(div-1)*divsiz;
  171.           sign1[occurcount] = sign2[occurcount] = s1+1;
  172.           occurcount++;
  173.         }
  174.  
  175.         /* Does the current planet go retrograde or direct? */
  176.  
  177.         if (!ignore[i] && (cp1.dir[i] < 0.0) != (cp2.dir[i] < 0.0) && !ignore2[0]) 
  178.         {
  179.           source[occurcount] = i;
  180.           aspect[occurcount] = aDir;
  181.           dest[occurcount] = cp2.dir[i] < 0.0;
  182.           time[occurcount] = RAbs(cp1.dir[i])/(RAbs(cp1.dir[i])+
  183.                              RAbs(cp2.dir[i]))*divsiz + (real)(div-1)*divsiz;
  184.           sign1[occurcount] = sign2[occurcount] = s1+1;
  185.           occurcount++;
  186.         }
  187.  
  188.         /* Now search for anything making an aspect to the current planet. */
  189.  
  190.         for (j = i+1; j <= cObj; j++) if (!ignore[j] && (fProg || FThing(j)))
  191.         {
  192.           for (k = 1; k <= us.nAsp; k++) if (FAcceptAspect(i, k, j))
  193.           {
  194.             d1 = cp1.obj[i]; d2 = cp2.obj[i];
  195.             e1 = cp1.obj[j]; e2 = cp2.obj[j];
  196.             if (MinDistance(d1, d2) < MinDistance(e1, e2)) 
  197.             {
  198.               SwapR(&d1, &e1);
  199.               SwapR(&d2, &e2);
  200.             }
  201.  
  202.             /* We are searching each aspect in turn. Let's subtract the  */
  203.             /* size of the aspect from the angular difference, so we can */
  204.             /* then treat it like a conjunction.                         */
  205.  
  206.             if (MinDistance(e1, Mod(d1-aspectangle[k])) <
  207.                 MinDistance(e2, Mod(d2+aspectangle[k])))
  208.             {
  209.               e1 = Mod(e1+aspectangle[k]);
  210.               e2 = Mod(e2+aspectangle[k]);
  211.             } 
  212.  
  213.             else
  214.             {
  215.               e1 = Mod(e1-aspectangle[k]);
  216.               e2 = Mod(e2-aspectangle[k]);
  217.             }
  218.  
  219.             /* Check to see if the aspect actually occurs during our    */
  220.             /* segment, making sure we take into account if one or both */
  221.             /* planets are retrograde or if they cross the Aries point. */
  222.  
  223.             f1 = e1-d1;
  224.  
  225.             if (RAbs(f1) > rDegHalf)
  226.               f1 -= RSgn(f1)*rDegMax;
  227.  
  228.             f2 = e2-d2;
  229.  
  230.             if (RAbs(f2) > rDegHalf)
  231.               f2 -= RSgn(f2)*rDegMax;
  232.  
  233.             if (MinDistance(Midpoint(d1, d2), Midpoint(e1, e2)) < rDegQuad && RSgn(f1) != RSgn(f2)) 
  234.             {
  235.               source[occurcount] = i;
  236.               aspect[occurcount] = k;
  237.               dest[occurcount] = j;
  238.  
  239.               /* Horray! The aspect occurs sometime during the interval.   */
  240.               /* Now we just have to solve an equation in two variables to */
  241.               /* find out where the "lines" cross, i.e. the aspect's time. */
  242.  
  243.               f1 = d2-d1;
  244.  
  245.               if (RAbs(f1) > rDegHalf)
  246.                 f1 -= RSgn(f1)*rDegMax;
  247.  
  248.               f2 = e2-e1;
  249.  
  250.               if (RAbs(f2) > rDegHalf)
  251.                 f2 -= RSgn(f2)*rDegMax;
  252.  
  253.               g = (RAbs(d1-e1) > rDegHalf ? (d1-e1)-RSgn(d1-e1)*rDegMax : d1-e1)/(f2-f1);
  254.  
  255.               time[occurcount] = g*divsiz + (real)(div-1)*divsiz;
  256.  
  257.               sign1[occurcount] = (int)(Mod(cp1.obj[i]+RSgn(cp2.obj[i]-cp1.obj[i])*
  258.                 (RAbs(cp2.obj[i]-cp1.obj[i]) > rDegHalf ? -1 : 1)*
  259.                 RAbs(g)*MinDistance(cp1.obj[i], cp2.obj[i]))/30.0)+1;
  260.  
  261.               sign2[occurcount] = (int)(Mod(cp1.obj[j]+
  262.                 RSgn(cp2.obj[j]-cp1.obj[j])*
  263.                 (RAbs(cp2.obj[j]-cp1.obj[j]) > rDegHalf ? -1 : 1)*
  264.                 RAbs(g)*MinDistance(cp1.obj[j], cp2.obj[j]))/30.0)+1;
  265.  
  266.               occurcount++;
  267.             }
  268.           }
  269.         }
  270.       }
  271.     }
  272.  
  273.     /* After all the aspects, etc, in the day have been located, sort   */
  274.     /* them by time at which they occur, so we can print them in order. */
  275.  
  276.     for (i = 1; i < occurcount; i++) 
  277.     {
  278.       j = i-1;
  279.       while (j >= 0 && time[j] > time[j+1])
  280.       {
  281.         SwapN(source[j], source[j+1]);
  282.         SwapN(aspect[j], aspect[j+1]);
  283.         SwapN(dest[j], dest[j+1]);
  284.         SwapR(&time[j], &time[j+1]);
  285.         SwapN(sign1[j], sign1[j+1]); SwapN(sign2[j], sign2[j+1]);
  286.         j--;
  287.       }
  288.     }
  289.  
  290.     /* Finally, loop through and display each aspect and when it occurs. */
  291.  
  292.     for (i = 0; i < occurcount; i++) 
  293.     {
  294.       s1 = (int)time[i]/60;
  295.       s2 = (int)time[i]-s1*60;
  296.       j = Day2;
  297.  
  298.       if (fYear || fProg)
  299.       {
  300.         l = Mon2;
  301.  
  302.         while(j > (k = DayInMonth(l, yea0)))
  303.         {
  304.           j -= k;
  305.           l++;
  306.         }
  307.       }
  308.       /* else `l' is uninitialized! */
  309.  
  310.       SetCI(ciSave, (fYear || fProg) ? l : Mon, j, yea0, DegToDec(time[i] / 60.0), Dst, Zon, Lon, Lat);
  311.       k = DayOfWeek(fYear || fProg ? l : Mon, j, yea0);
  312.       AnsiColor(kRainbowA[k + 1]);
  313.       sprintf(sz, "(%c%c%c) ", chDay3(k)); PrintSz(sz);
  314.       AnsiColor(kDefault);
  315.  
  316.       sprintf(sz, "%s %s ",
  317.         SzDate( (fYear || fProg) ? l : Mon, j, yea0, fFalse),
  318.         SzTime(s1, s2)); PrintSz(sz);
  319.  
  320.       PrintAspect(source[i], sign1[i],
  321.         (int)RSgn(cp1.dir[source[i]])+(int)RSgn(cp2.dir[source[i]]),
  322.         aspect[i], dest[i], sign2[i],
  323.         (int)RSgn(cp1.dir[dest[i]])+(int)RSgn(cp2.dir[dest[i]]),
  324.         (char)(fProg ? 'e' : 'd'));
  325.  
  326.       PrintInDay(source[i], aspect[i], dest[i]);
  327.     }
  328.   }
  329.   }
  330.  
  331.   /* Recompute original chart placements as we've overwritten them. */
  332.  
  333.   ciCore = ciMain;
  334.   CastChart(fTrue);
  335. }
  336.  
  337.  
  338. /* Search through a month, year, or years, and print out the times of exact */
  339. /* transits where planets in the time frame make aspect to the planets in   */
  340. /* some other chart, as specified with the -t switch. To do this, we cast   */
  341. /* charts for the start and end of each month, or within a month, and do an */
  342. /* equation check for aspects to the other base chart during the interval.  */
  343.  
  344. void ChartTransitSearch(fProg)
  345. bool fProg;
  346. {
  347.   real planet3[objMax], house3[cSign+1], ret3[objMax], time[MAXINDAY];
  348.   char sz[cchSzDef];
  349.   int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY], sign[MAXINDAY],
  350.     isret[MAXINDAY], M1, M2, Y1, Y2, occurcount, div, i, j, k, s1, s2, s3;
  351.   real divsiz, daysiz, d, e1, e2, f1, f2;
  352.  
  353.   for (i = 1; i <= cSign; i++)
  354.     house3[i] = house[i];
  355.  
  356.   for (i = 1; i <= cObj; i++)
  357.   {
  358.     planet3[i] = planet[i];
  359.     ret3[i] = ret[i];
  360.   }
  361.  
  362.   /* Hacks: Searching month number zero means to search the whole year     */
  363.   /* instead, month by month. Searching a negative month means to search   */
  364.   /* multiple years, with the span off the year stored in the "day" field. */
  365.  
  366.   Y1 = Y2 = Yea2;
  367.   M1 = M2 = Mon2;
  368.   if (Mon2 < 1) 
  369.   {
  370.     M1 = 1; M2 = 12;
  371.     if (Mon2 < 0) 
  372.     {
  373.       if (Day2 < 1) 
  374.       {
  375.         Y1 = Yea2 + Day2 + 1; Y2 = Yea2;
  376.       } 
  377.  
  378.       else
  379.       {
  380.         Y1 = Yea2; Y2 = Yea2 + Day2 - 1;
  381.       }
  382.     }
  383.   }
  384.  
  385.   /* Start searching the year or years in question for any transits. */
  386.  
  387.   for (Yea2 = Y1; Yea2 <= Y2; Yea2++)
  388.  
  389.   /* Start searching the month or months in question for any transits. */
  390.  
  391.   for (Mon2 = M1; Mon2 <= M2; Mon2++)
  392.   {
  393.     daysiz = (real)DayInMonth(Mon2, Yea2)*24.0*60.0;
  394.     divsiz = daysiz / (real)us.nDivision;
  395.  
  396.     /* Cast chart for beginning of month and store it for future use. */
  397.  
  398.     SetCI(ciCore, Mon2, 1, Yea2, 0.0, Dst2, Zon2, Lon2, Lat2);
  399.  
  400.     if( (us.fProgress = fProg) )
  401.     {
  402.       is.JDp = MdytszToJulian(MM, DD, YY, 0.0, Dst2, Zon2);
  403.       ciCore = ciMain;
  404.     }
  405.  
  406.     for (i = 1; i <= oNorm; i++)
  407.       SwapN(ignore[i], ignore2[i]);
  408.  
  409.     CastChart(fTrue);
  410.  
  411.     for (i = 1; i <= oNorm; i++)
  412.       SwapN(ignore[i], ignore2[i]);
  413.  
  414.     for (i = 1; i <= cSign; i++)
  415.       cp2.cusp[i] = house[i];
  416.  
  417.     for (i = 1; i <= oCore; i++)
  418.     {
  419.       cp2.obj[i] = planet[i];
  420.       cp2.dir[i] = ret[i];
  421.     }
  422.  
  423.     /* Divide our month into segments and then search each segment in turn. */
  424.  
  425.     for (div = 1; div <= us.nDivision; div++) 
  426.     {
  427.       occurcount = 0;
  428.  
  429.       /* Cast the chart for the ending time of the present segment, and */
  430.       /* copy the start time chart from the previous end time chart.    */
  431.  
  432.       d = 1.0 + (daysiz/24.0/60.0)*(real)div/(real)us.nDivision;
  433.       SetCI(ciCore, Mon2, (int)d, Yea2, DegToDec(RFract(d)*24.0), Dst2, Zon2, Lon2, Lat2);
  434.  
  435.       if (fProg)
  436.       {
  437.         is.JDp = MdytszToJulian(MM, DD, YY, 0.0, Dst2, Zon2);
  438.         ciCore = ciMain;
  439.       }
  440.  
  441.       for (i = 1; i <= oNorm; i++)
  442.         SwapN(ignore[i], ignore2[i]);
  443.  
  444.       CastChart(fTrue);
  445.  
  446.       for (i = 1; i <= oNorm; i++)
  447.         SwapN(ignore[i], ignore2[i]);
  448.  
  449.       for (i = 1; i <= cSign; i++)
  450.       {
  451.         cp1.cusp[i] = cp2.cusp[i]; cp2.cusp[i] = house[i];
  452.       }
  453.  
  454.       for (i = 1; i <= oCore; i++)
  455.       {
  456.         cp1.obj[i] = cp2.obj[i]; cp1.dir[i] = cp2.dir[i];
  457.         cp2.obj[i] = planet[i];  cp2.dir[i] = ret[i];
  458.       }
  459.  
  460.       /* Now search through the present segment for any transits. Note that */
  461.       /* stars can be transited, but they can't make transits themselves.   */
  462.  
  463.       for (i = 1; i <= cObj; i++) if (!ignore[i])
  464.         for (j = 1; j <= oNorm; j++) if (!ignore2[j] && (fProg || FThing(j)))
  465.  
  466.           /* Between each pair of planets, check if they make any aspects. */
  467.  
  468.           for (k = 1; k <= us.nAsp; k++) if (FAcceptAspect(i, k, j)) 
  469.           {
  470.             d = planet3[i]; e1 = cp1.obj[j]; e2 = cp2.obj[j];
  471.  
  472.             if (MinDistance(e1, Mod(d-aspectangle[k])) <
  473.                 MinDistance(e2, Mod(d+aspectangle[k])))
  474.             {
  475.               e1 = Mod(e1+aspectangle[k]);
  476.               e2 = Mod(e2+aspectangle[k]);
  477.             }
  478.             else
  479.             {
  480.               e1 = Mod(e1-aspectangle[k]);
  481.               e2 = Mod(e2-aspectangle[k]);
  482.             }
  483.  
  484.             /* Check to see if the present aspect actually occurs during the */
  485.             /* segment, making sure we check any Aries point crossings.      */
  486.  
  487.             f1 = e1-d;
  488.  
  489.             if (RAbs(f1) > rDegHalf)
  490.               f1 -= RSgn(f1)*rDegMax;
  491.  
  492.             f2 = e2-d;
  493.  
  494.             if (RAbs(f2) > rDegHalf)
  495.               f2 -= RSgn(f2)*rDegMax;
  496.  
  497.             if (MinDistance(d, Midpoint(e1, e2)) < rDegQuad &&
  498.               RSgn(f1) != RSgn(f2) && occurcount < MAXINDAY) {
  499.  
  500.               /* Ok, we have found a transit. Now determine the time */
  501.               /* and save this transit in our list to be printed.    */
  502.  
  503.               source[occurcount] = j;
  504.               aspect[occurcount] = k;
  505.               dest[occurcount] = i;
  506.               time[occurcount] = RAbs(f1)/(RAbs(f1)+RAbs(f2))*divsiz + (real)(div-1)*divsiz;
  507.  
  508.               sign[occurcount] = (int)(Mod(  MinDistance(cp1.obj[j], Mod(d-aspectangle[k])) <
  509.                                              MinDistance(cp2.obj[j], Mod(d+aspectangle[k])) ?
  510.                                              d-aspectangle[k] : d+aspectangle[k])/30.0)+1;
  511.  
  512.               isret[occurcount] = (int)RSgn(cp1.dir[j]) +
  513.                                   (int)RSgn(cp2.dir[j]);
  514.               occurcount++;
  515.             }
  516.           }
  517.  
  518.       /* After all transits located, sort them by time at which they occur. */
  519.  
  520.       for (i = 1; i < occurcount; i++) 
  521.       {
  522.         j = i-1;
  523.         while (j >= 0 && time[j] > time[j+1])
  524.         {
  525.           SwapN(source[j], source[j+1]);
  526.           SwapN(aspect[j], aspect[j+1]);
  527.           SwapN(dest[j], dest[j+1]);
  528.           SwapR(&time[j], &time[j+1]);
  529.           SwapN(sign[j], sign[j+1]);
  530.           SwapN(isret[j], isret[j+1]);
  531.           j--;
  532.         }
  533.       }
  534.  
  535.       /* Now loop through list and display all the transits. */
  536.  
  537.       for (i = 0; i < occurcount; i++) 
  538.       {
  539.         s1 = (_int)time[i]/24/60;
  540.         s3 = (_int)time[i]-s1*24*60;
  541.         s2 = s3/60;
  542.         s3 = s3-s2*60;
  543.         SetCI(ciSave, Mon2, s1+1, Yea2, DegToDec((real)
  544.           ((_int)time[i]-s1*24*60) / 60.0), Dst2, Zon2, Lon2, Lat2);
  545.         sprintf(sz, "%s %s ",
  546.           SzDate(Mon2, s1+1, Yea2, fFalse), SzTime(s2, s3)); PrintSz(sz);
  547.         PrintAspect(source[i], sign[i], isret[i], aspect[i],
  548.           dest[i], SFromZ(planet3[dest[i]]), (int)RSgn(ret3[dest[i]]),
  549.           (char)(fProg ? 'u' : 't'));
  550.  
  551.         /* Check for a Solar, Lunar, or any other return. */
  552.  
  553.         if (aspect[i] == aCon && source[i] == dest[i]) 
  554.         {
  555.           AnsiColor(kWhite);
  556.           sprintf(sz, " (%s Return)", source[i] == oSun ? "Solar" :
  557.             (source[i] == oMoo ? "Lunar" : szObjName[source[i]]));
  558.           PrintSz(sz);
  559.         }
  560.         PrintL();
  561. #ifdef INTERPRET
  562.         if (us.fInterpret)
  563.           InterpretTransit(source[i], aspect[i], dest[i]);
  564. #endif
  565.         AnsiColor(kDefault);
  566.       }
  567.     }
  568.   }
  569. }
  570.  
  571.  
  572. /* Display a list of planetary rising times relative to the local horizon */
  573. /* for the day indicated in the chart information, as specified with the  */
  574. /* -Zd switch. For the day, the time each planet rises (transits horizon  */
  575. /* in East half of sky), sets (transits horizon in West), reaches its     */
  576. /* zenith point (transits meridian in South half of sky), and nadirs      */
  577. /* transits meridian in North), is displayed.                             */
  578.  
  579. void ChartInDayHorizon()
  580. {
  581.   char sz[cchSzDef];
  582.  
  583.   int source[MAXINDAY], type[MAXINDAY], sign[MAXINDAY],
  584.     fRet[MAXINDAY], occurcount, division, div, s1, s2, i, j, fT;
  585.  
  586.   real time[MAXINDAY], rgalt1[objMax], rgalt2[objMax], azialt[MAXINDAY],
  587.     azi1, azi2, alt1, alt2, lon, lat, mc1, mc2, xA, yA, xV, yV, d, k;
  588.  
  589.   fT = us.fSiderial; us.fSiderial = fFalse;
  590.   lon = RFromD(Mod(Lon)); lat = RFromD(Lat);
  591.   division = us.nDivision * 4;
  592.   occurcount = 0;
  593.  
  594.   ciCore = ciMain; ciCore.tim = 0.0;
  595.   CastChart(fTrue);
  596.   mc2 = RFromD(planet[oMC]); k = RFromD(planetalt[oMC]);
  597.   EclToEqu(&mc2, &k);
  598.  
  599.   for (i = 1; i <= cSign; i++)
  600.   {
  601.     cp2.cusp[i] = house[i];
  602.     cp2.house[i] = inhouse[i];
  603.   }
  604.  
  605.   for (i = 1; i <= cObj; i++)
  606.   {
  607.     cp2.obj[i] = planet[i];
  608.     rgalt2[i] = planetalt[i];
  609.     cp2.dir[i] = ret[i];
  610.   }
  611.  
  612.   /* Loop thorough the day, dividing it into a certain number of segments. */
  613.   /* For each segment we get the planet positions at its endpoints.        */
  614.  
  615.   for (div = 1; div <= division; div++)
  616.   {
  617.     ciCore = ciMain; ciCore.tim = DegToDec(24.0*(real)div/(real)division);
  618.     CastChart(fTrue);
  619.     mc1 = mc2;
  620.     mc2 = RFromD(planet[oMC]); k = RFromD(planetalt[oMC]);
  621.     EclToEqu(&mc2, &k);
  622.  
  623.     for (i = 1; i <= cSign; i++) 
  624.     {
  625.       cp1.cusp[i] = cp2.cusp[i]; cp1.house[i] = cp2.house[i];
  626.       cp2.cusp[i] = house[i];    cp2.house[i] = inhouse[i];
  627.     }
  628.  
  629.     for (i = 1; i <= cObj; i++)
  630.     {
  631.       cp1.obj[i] = cp2.obj[i]; cp2.obj[i] = planet[i];
  632.       rgalt1[i] = rgalt2[i]; rgalt2[i] = planetalt[i];
  633.       cp1.dir[i] = cp2.dir[i]; cp2.dir[i] = ret[i];
  634.     }
  635.  
  636.     /* For our segment, check to see if each planet during it rises, sets, */
  637.     /* reaches its zenith, or reaches its nadir.                           */
  638.  
  639.     for (i = 1; i <= cObj; i++) if (!ignore[i] && FThing(i)) 
  640.     {
  641.       EclToHorizon(&azi1, &alt1, cp1.obj[i], rgalt1[i], lon, lat, mc1);
  642.       EclToHorizon(&azi2, &alt2, cp2.obj[i], rgalt2[i], lon, lat, mc2);
  643.       j = 0;
  644.  
  645.       /* Check for transits to the horizon. */
  646.  
  647.       if ((alt1 > 0.0) != (alt2 > 0.0))
  648.       {
  649.         d = RAbs(alt1)/(RAbs(alt1)+RAbs(alt2));
  650.         k = Mod(azi1 + d*MinDifference(azi1, azi2));
  651.         j = 1 + 2*(MinDistance(k, rDegHalf) < rDegQuad);
  652.       }
  653.  
  654.       /* Check for transits to the meridian. */
  655.  
  656.       else if (RSgn(MinDifference(azi1, rDegQuad)) !=
  657.                RSgn(MinDifference(azi2, rDegQuad))) 
  658.       {
  659.         j = 2 + 2*(MinDistance(azi1, rDegQuad) < rDegQuad);
  660.         d = RAbs(azi1 - (j > 2 ? rDegQuad : 270.0))/MinDistance(azi1, azi2);
  661.         k = alt1 + d*(alt2-alt1);
  662.       }
  663.  
  664.       if (j && occurcount < MAXINDAY)
  665.       {
  666.         source[occurcount] = i;
  667.         type[occurcount] = j;
  668.         time[occurcount] = 24.0*((real)(div-1)+d)/(real)division*60.0;
  669.         sign[occurcount] = (int)Mod(cp1.obj[i] +
  670.           d*MinDifference(cp1.obj[i], cp2.obj[i]))/30 + 1;
  671.         fRet[occurcount] = (int)RSgn(cp1.dir[i]) + (int)RSgn(cp2.dir[i]);
  672.         azialt[occurcount] = k;
  673.         ciSave = ciMain;
  674.         ciSave.tim = DegToDec(time[occurcount] / 60.0);
  675.         occurcount++;
  676.       }
  677.     }
  678.   }
  679.  
  680.   /* Sort each event in order of time when it happens during the day. */
  681.  
  682.   for (i = 1; i < occurcount; i++) 
  683.   {
  684.     j = i-1;
  685.     while (j >= 0 && time[j] > time[j+1]) 
  686.     {
  687.       SwapN(source[j], source[j+1]);
  688.       SwapN(type[j], type[j+1]);
  689.       SwapR(&time[j], &time[j+1]);
  690.       SwapN(sign[j], sign[j+1]);
  691.       SwapN(fRet[j], fRet[j+1]);
  692.       SwapR(&azialt[j], &azialt[j+1]);
  693.       j--;
  694.     }
  695.   }
  696.  
  697.   /* Finally display the list showing each event and when it occurs. */
  698.  
  699.   for (i = 0; i < occurcount; i++)   
  700.   {
  701.     ciSave = ciMain;
  702.     ciSave.tim = DegToDec(time[i] / 60.0);
  703.     j = DayOfWeek(Mon, Day, Yea);
  704.     AnsiColor(kRainbowA[j + 1]);
  705.     sprintf(sz, "(%c%c%c) ", chDay3(j)); PrintSz(sz);
  706.     AnsiColor(kDefault);
  707.     s1 = (int)time[i]/60;
  708.     s2 = (int)time[i]-s1*60;
  709.     sprintf(sz, "%s %s ", SzDate(Mon, Day, Yea, fFalse), SzTime(s1, s2));
  710.     PrintSz(sz);
  711.     AnsiColor(kObjA[source[i]]);
  712.     sprintf(sz, "%7.7s ", szObjName[source[i]]); PrintSz(sz);
  713.     AnsiColor(kSignA(sign[i]));
  714.     sprintf(sz, "%c%c%c%c%c ",
  715.       fRet[i] > 0 ? '(' : (fRet[i] < 0 ? '[' : '<'), chSig3(sign[i]),
  716.       fRet[i] > 0 ? ')' : (fRet[i] < 0 ? ']' : '>')); PrintSz(sz);
  717.     AnsiColor(kElemA[type[i]-1]);
  718.     if (type[i] == 1)
  719.       PrintSz("rises  ");
  720.     else if (type[i] == 2)
  721.       PrintSz("zeniths");
  722.     else if (type[i] == 3)
  723.       PrintSz("sets   ");
  724.     else
  725.       PrintSz("nadirs ");
  726.     AnsiColor(kDefault);
  727.     PrintSz(" at ");
  728.  
  729.     if (type[i] & 1)
  730.     {
  731.       j = (int)(RFract(azialt[i])*60.0);
  732.       sprintf(sz, "%3d%c%02d'", (int)azialt[i], chDeg1, j); PrintSz(sz);
  733.  
  734.       /* For rising and setting events, we'll also display a direction  */
  735.       /* vector to make the 360 degree azimuth value thought of easier. */
  736.  
  737.       xA = RCosD(azialt[i]); yA = RSinD(azialt[i]);
  738.       if (RAbs(xA) < RAbs(yA)) {
  739.         xV = RAbs(xA / yA); yV = 1.0;
  740.       } else {
  741.         yV = RAbs(yA / xA); xV = 1.0;
  742.       }
  743.       sprintf(sz, " (%.2f%c %.2f%c)",
  744.         yV, yA < 0.0 ? 's' : 'n', xV, xA > 0.0 ? 'e' : 'w'); PrintSz(sz);
  745.     } 
  746.  
  747.     else
  748.       PrintAltitude(azialt[i]);
  749.  
  750.     PrintL();
  751.   }
  752.  
  753.   /* Recompute original chart placements as we've overwritten them. */
  754.  
  755.   ciCore = ciMain;
  756.   us.fSiderial = fT;
  757.   CastChart(fTrue);
  758. }
  759.  
  760.  
  761. /* Print out an ephemeris - the positions of the planets (at the time in the */
  762. /* current chart) each day during a specified month, as done with the -E     */
  763. /* switch. Display the ephemeris for the whole year if -Ey is in effect.     */
  764.  
  765. void ChartEphemeris()
  766. {
  767.   char sz[cchSzDef];
  768.   int yea, yea1, yea2, mon, mon1, mon2, daysiz, i, j, s, d, m;
  769.  
  770.   /* If -Ey is in effect, then loop through all months in the whole year. */
  771.  
  772.   if (us.nEphemYears) 
  773.   {
  774.     yea1 = Yea; yea2 = yea1 + us.nEphemYears - 1; mon1 = 1; mon2 = 12;
  775.   } 
  776.  
  777.   else
  778.   {
  779.     yea1 = yea2 = Yea; mon1 = mon2 = Mon;
  780.   }
  781.  
  782.   /* Loop through the year or years in question. */
  783.  
  784.   for (yea = yea1; yea <= yea2; yea++)
  785.  
  786.   /* Loop through the month or months in question, printing each ephemeris. */
  787.  
  788.   for (mon = mon1; mon <= mon2; mon++) 
  789.   {
  790.     daysiz = DayInMonth(mon, yea);
  791.     PrintSz(us.fEuroDate ? "Dy/Mo/Yr" : "Mo/Dy/Yr");
  792.     for (j = 1; j <= cObj; j++) 
  793.     {
  794.       if (!ignore[j] && FThing(j)) 
  795.       {
  796.         sprintf(sz, "  %s%c%c%c%c%s ", is.fSeconds ? "  " : "", chObj3(j),
  797.           szObjName[j][3] != 0 ? szObjName[j][3] : ' ',
  798.           is.fSeconds ? "   " : ""); PrintSz(sz);
  799.       }
  800.     }
  801.     PrintL();
  802.     for (i = 1; i <= daysiz; i = AddDay(mon, i, yea, 1)) {
  803.  
  804.       /* Loop through each day in the month, casting a chart for that day. */
  805.  
  806.       SetCI(ciCore, mon, i, yea, Tim, Dst, Zon, Lon, Lat);
  807.       CastChart(fTrue);
  808.       PrintSz(SzDate(mon, i, yea, -1));
  809.       PrintCh(' ');
  810.  
  811.       for (j = 1; j <= cObj; j++)
  812.         if (!ignore[j] && FThing(j)) 
  813.         {
  814.           if (is.fSeconds)
  815.             PrintZodiac(planet[j]);
  816.  
  817.           else
  818.           {
  819.             AnsiColor(kObjA[j]);
  820.             s = SFromZ(planet[j]);
  821.             d = (int)planet[j] - (s-1)*30;
  822.             m = (int)(RFract(planet[j])*60.0);
  823.             sprintf(sz, "%2d%s%02d", d, szSignAbbrev[s], m); PrintSz(sz);
  824.           }
  825.           PrintCh((char)(ret[j] >= 0.0 ? ' ' : '.'));
  826.         }
  827.       PrintL();
  828.       AnsiColor(kDefault);
  829.     }
  830.     if (mon < mon2 || yea < yea2)
  831.       PrintL();
  832.   }
  833. }
  834.  
  835. /* charts3.c */
  836.